package com.yang.core.plugins.retry;

import com.yang.core.model.ExceptionContext;
import com.yang.core.model.RequestContext;
import com.yang.core.model.ResponseContext;
import com.yang.core.api.RestClientInterceptor;
import com.yang.core.config.RestClientProperties;
import lombok.extern.slf4j.Slf4j;

import java.time.Duration;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 重试拦截器
 */
@Slf4j
public class RetryInterceptor implements RestClientInterceptor {

    private final RestClientProperties.Retry retryConfig;

    public RetryInterceptor(RestClientProperties.Retry retryConfig) {
        this.retryConfig = retryConfig;
    }

    @Override
    public void preRequest(RequestContext context) {
        // 在第一次请求时添加重试计数属性
        context.setAttribute("retryCount", 0);
    }

    @Override
    public void postResponse(ResponseContext context) {
        // 响应成功，重置重试计数
        // 在拦截器模式下无法修改请求状态
    }

    @Override
    public void onError(ExceptionContext context) {
        Integer retryCount = (Integer) context.getAttribute("retryCount");
        if (retryCount == null) {
            retryCount = 0;
        }

        if (shouldRetry(context, context.getException(), retryCount)) {
            int newRetryCount = retryCount + 1;
            context.setShouldRetry(true);

            log.info("准备重试请求: {} {} - 第{}次重试, 异常: {}",
                    context.getMethod(),
                    context.getUrl(),
                    newRetryCount,
                    context.getException().getClass().getSimpleName());

            // 添加延迟
            try {
                long delay = calculateDelay(newRetryCount);
                Thread.sleep(delay);
                log.debug("重试延迟: {}ms", delay);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.warn("重试延迟被中断", e);
            }
        } else {
            log.warn("重试次数已达上限或异常不满足重试条件: {} {} - 重试次数: {}",
                    context.getMethod(),
                    context.getUrl(),
                    retryCount);
        }
    }

    private boolean shouldRetry(ExceptionContext context, Exception exception, int retryCount) {
        if (retryCount >= retryConfig.getMaxAttempts() - 1) {
            return false;
        }

        // 检查异常类型是否满足重试条件
        if (!isRetryableException(exception)) {
            return false;
        }

        // 可以根据HTTP方法进行更细粒度的控制
        // 例如：GET请求通常可以重试，而POST请求可能不行
        String method = context.getMethod();
        return isRetryableMethod(method);
    }

    private boolean isRetryableException(Exception exception) {
        String retryOn = retryConfig.getRetryOn();
        if (retryOn == null || retryOn.isEmpty()) {
            return true; // 默认重试所有异常
        }

        String[] conditions = retryOn.split(",");
        for (String condition : conditions) {
            String trimmedCondition = condition.trim().toUpperCase();
            if (matchesCondition(exception, trimmedCondition)) {
                return true;
            }
        }

        return false;
    }

    private boolean matchesCondition(Exception exception, String condition) {
        switch (condition) {
            case "TIMEOUT":
                return exception instanceof java.util.concurrent.TimeoutException;
            case "CONNECTION_ERROR":
                return exception instanceof java.net.ConnectException ||
                       exception instanceof java.net.SocketException;
            case "SERVER_ERROR":
                return exception instanceof org.springframework.web.client.HttpServerErrorException;
            default:
                return true; // 默认匹配所有异常
        }
    }

    private boolean isRetryableMethod(String method) {
        // 通常GET、HEAD、DELETE请求是幂等的，可以重试
        // POST、PUT、PATCH请求可能不是幂等的，需要谨慎重试
        switch (method.toUpperCase()) {
            case "GET":
            case "HEAD":
            case "DELETE":
                return true;
            case "POST":
            case "PUT":
            case "PATCH":
                // 对于非幂等请求，默认不重试（可根据配置扩展）
                return false;
            default:
                return true;
        }
    }

    private long calculateDelay(int retryCount) {
        // 指数退避算法，加上随机抖动
        long baseDelay = retryConfig.getInitialDelay().toMillis();
        double multiplier = retryConfig.getBackoffMultiplier();
        long maxDelay = retryConfig.getMaxDelay().toMillis();

        long delay = (long) (baseDelay * Math.pow(multiplier, retryCount - 1));

        // 添加抖动，避免多个请求同时重试
        long jitter = (long) (delay * 0.1 * ThreadLocalRandom.current().nextDouble());
        delay = delay + jitter;

        return Math.min(delay, maxDelay);
    }

    /**
     * 需要重试的特殊异常
     */
    public static class RetryNeededException extends RuntimeException {
        public RetryNeededException(String message, Throwable cause) {
            super(message, cause);
        }
    }
}